package rpc.utils;

/*********
 *
 *
 *@author 197
 *@date 2020/7/20 16:29
 *
 **/

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BeanToMapUtil {

  /**
   * 将一个 Map 对象转化为一个 JavaBean
   *
   * @param type 要转化的类型
   * @param map  包含属性值的 map
   */
  public static <T> T convertMap(Class<T> type, Map<String, Object> map) {

    T obj = (T) ReflectionUtils.newObject(type.getName());

    List<ClassMethodInfo> setMethodName = Arrays.stream(type.getMethods()).filter(method -> method.getName().startsWith("set")).map(ClassMethodInfo::new)
        .collect(Collectors.toList());
    setMethodName.forEach(classMethodInfo -> {
      if (map.containsKey(classMethodInfo.getPropertyName())) {
        Object value = map.get(classMethodInfo.getPropertyName());
        classMethodInfo.invoke(obj, value);
      }
    });

    return obj;
  }

  /**
   * 将一个 JavaBean 对象转化为一个  Map
   *
   * @param bean 要转化的JavaBean 对象
   * @return 转化出来的  Map 对象
   * @throws IntrospectionException    如果分析类属性失败
   * @throws IllegalAccessException    如果实例化 JavaBean 失败
   * @throws InvocationTargetException 如果调用属性的 setter 方法失败
   */
  public static Map<String, Object> convertBean(Object bean)
      throws IntrospectionException, IllegalAccessException, InvocationTargetException {
    Class type = bean.getClass();
    Map<String, Object> returnMap = new HashMap<String, Object>();
    BeanInfo beanInfo = Introspector.getBeanInfo(type);

    PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
    for (int i = 0; i < propertyDescriptors.length; i++) {
      PropertyDescriptor descriptor = propertyDescriptors[i];
      String propertyName = descriptor.getName();
      if (!propertyName.equals("class")) {
        Method readMethod = descriptor.getReadMethod();
        Object result = readMethod.invoke(bean);
        if (result != null) {
          returnMap.put(propertyName, result);
        } else {
          returnMap.put(propertyName, "");
        }
      }
    }
    return returnMap;
  }
}

class ClassMethodInfo {

  private final Method method;
  private final String propertyName;

  public ClassMethodInfo(Method m) {
    this.method = m;
    String methodName = m.getName();
    this.propertyName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
  }

  public String getPropertyName() {
    return propertyName;
  }
  void invoke(Object obj, Object value) {
    ReflectionUtils.invoke(method, obj, value);
  }
}